enum PhyObjectType {
    Player = 1,
    Terrian = 2,
    Role = 3,
}

class PhyObject {
    public body: Box2D.Dynamics.b2Body
    protected _type: PhyObjectType
    protected _container: egret.DisplayObjectContainer
    public get Type(): PhyObjectType {
        return this._type
    }
    constructor(type: PhyObjectType, container: egret.DisplayObjectContainer) {
        this._type = type
        this._container = container
    }
}
//====================================================
class TerrianPhyObject extends PhyObject {
    private _bmp: egret.Bitmap
    private _arch: Box2D.Common.Math.b2Vec2
    public get Arch(): Box2D.Common.Math.b2Vec2 {
        return this._arch
    }

    constructor(container: egret.DisplayObjectContainer, world: Box2D.Dynamics.b2World, width, height: number, x, y: number, p: number) {
        super(PhyObjectType.Terrian, container)

        this._bmp = new egret.Bitmap
        this._bmp.texture = RES.getRes("stone_png");
        this._container.addChild(this._bmp)

        {
            let bodyDef = new Box2D.Dynamics.b2BodyDef()
            bodyDef.type = Box2D.Dynamics.b2Body.b2_staticBody
            bodyDef.bullet = true
            bodyDef.linearDamping = 0.1
            bodyDef.angularDamping = 0.2
            bodyDef.fixedRotation = false
            bodyDef.allowSleep = true
            bodyDef.position.x = x
            bodyDef.position.y = y
            bodyDef.angle = Math.PI / 2

            let fixtureDef = new Box2D.Dynamics.b2FixtureDef()
            fixtureDef.density = 1
            fixtureDef.friction = 0
            fixtureDef.restitution = 0.8

            this.body = world.CreateBody(bodyDef)
            this.body.SetUserData(this)

            {
                let shape = new Box2D.Collision.Shapes.b2PolygonShape()
                shape.SetAsBox(PhyScene.PhyLen(width) / 2, PhyScene.PhyLen(height) / 2)
                fixtureDef.shape = shape
                this.body.CreateFixture(fixtureDef)
            }
            {
                let shape = new Box2D.Collision.Shapes.b2CircleShape()
                shape.SetRadius(PhyScene.PhyLen(5))
                shape.SetLocalPosition((new Box2D.Common.Math.b2Vec2(-p * PhyScene.PhyLen(width / 2 - 10), 0)))
                fixtureDef.shape = shape
                this.body.CreateFixture(fixtureDef)
                this._arch = shape.GetLocalPosition()
                this._arch = this.body.GetWorldPoint(shape.GetLocalPosition())
            }
        }

        this._bmp.width = height
        this._bmp.height = width
        this._bmp.anchorOffsetX = this._bmp.width / 2
        this._bmp.anchorOffsetY = this._bmp.height / 2

        this._bmp.x = PhyScene.EgretLen(x)
        this._bmp.y = PhyScene.EgretLen(y)
    }

    public RefreshBox(width, height: number) {
        let pos = this.body.GetPosition()
        this._bmp.width = width
        this._bmp.height = height
        this._bmp.anchorOffsetX = this._bmp.width / 2
        this._bmp.anchorOffsetY = this._bmp.height / 2

        this._bmp.x = PhyScene.EgretLen(pos.x)
        this._bmp.y = PhyScene.EgretLen(pos.y)
    }

    public Release() {
        this._container.removeChild(this._bmp)
    }
}
//====================================================
class PlayerPhyObject extends PhyObject {
    private _bmp: egret.Bitmap

    constructor(container: egret.DisplayObjectContainer, world: Box2D.Dynamics.b2World, size: number) {
        super(PhyObjectType.Player, container)
        this._bmp = new egret.Bitmap
        this._bmp.texture = RES.getRes("player_png");
        this._container.addChild(this._bmp)

        {
            let bodyDef = new Box2D.Dynamics.b2BodyDef()
            bodyDef.type = Box2D.Dynamics.b2Body.b2_dynamicBody
            bodyDef.bullet = true
            bodyDef.linearDamping = 0
            bodyDef.angularDamping = 0
            bodyDef.fixedRotation = false
            bodyDef.allowSleep = true
            bodyDef.position.x = 0
            bodyDef.position.y = 0 //App.StageUtils.getHeight() / 2 / this._p2m
            bodyDef.angle = Math.PI / 2

            let fixtureDef = new Box2D.Dynamics.b2FixtureDef()
            fixtureDef.density = 1
            fixtureDef.friction = 0
            fixtureDef.restitution = 0.8

            this.body = world.CreateBody(bodyDef)
            this.body.ApplyImpulse(new Box2D.Common.Math.b2Vec2(8, 0), this.body.GetPosition())
            this.body.SetUserData(this)
            this.RefreshPos()
            {
                let shape = new Box2D.Collision.Shapes.b2CircleShape()
                shape.SetRadius(PhyScene.PhyLen(size))
                fixtureDef.shape = shape
                this.body.CreateFixture(fixtureDef)
            }
        }

        this._bmp.width = size * 2
        this._bmp.height = size * 2
        this._bmp.anchorOffsetX = this._bmp.width / 2
        this._bmp.anchorOffsetY = this._bmp.height / 2
    }
    public RefreshPos() {
        let pos = this.body.GetPosition()
        this._bmp.x = PhyScene.EgretLen(pos.x)
        this._bmp.y = PhyScene.EgretLen(pos.y)

        let v = this.body.GetLinearVelocity()
        console.log("GetLinearVelocity: " + v.x + "," + v.y)
        if (v.x > 10) {
            v.x = v.x - 0.2
        }
        this.body.SetLinearVelocity(v)
    }
    public Release() {
        this._container.removeChild(this._bmp)
    }
}

//====================================================
class RolePhyObject extends PhyObject {
    private _bmp: egret.Bitmap = null
    private _joint: Box2D.Dynamics.Joints.b2Joint
    private _world: Box2D.Dynamics.b2World
    public get Joint(): Box2D.Dynamics.Joints.b2Joint {
        return this._joint
    }

    constructor(container: egret.DisplayObjectContainer, world: Box2D.Dynamics.b2World, player: PlayerPhyObject, terrian: TerrianPhyObject) {
        super(PhyObjectType.Role, container)
        this._world = world

        let joinDef = new Box2D.Dynamics.Joints.b2RevoluteJointDef()
        joinDef.Initialize(terrian.body, player.body, terrian.Arch)
        joinDef.enableMotor = true
        joinDef.enableLimit = false
        joinDef.collideConnected = false
        joinDef.motorSpeed = -100
        joinDef.maxMotorTorque = 1800
        this._joint = this._world.CreateJoint(joinDef)

        this._bmp = new egret.Bitmap
        this._bmp.texture = RES.getRes("player_png");
        this._container.addChild(this._bmp)

        let pos1 = this._joint.GetAnchorA()
        let pos2 = this._joint.GetBodyB().GetPosition()

        let length = Math.sqrt(Math.pow(pos1.x - pos2.x, 2) + Math.pow(pos1.y - pos2.y, 2))
        this._bmp.width = 5
        this._bmp.height = PhyScene.EgretLen(length)

        this._bmp.x = PhyScene.EgretLen(pos1.x)
        this._bmp.y = PhyScene.EgretLen(pos1.y)
        //this._bmp.skewX = (pos1.y - pos2.y)/ (pos1.x - pos2.x)
        this.RefreshPos()
    }

    public RefreshPos() {
        if (this._bmp != null) {
            let pos1 = this._joint.GetAnchorA()
            let pos2 = this._joint.GetBodyB().GetPosition()
            let pos = pos2
            pos.x = pos2.x - pos1.x
            pos.y = pos2.y - pos1.y
            let angle = Math.atan2(pos.y, pos.x)// - Math.atan2(pos1.y, pos1.x)
            angle = (angle / Math.PI * 180) - 90
            //console.log("angle: " + pos.x + "," + pos.y)
            console.log("angle: " + angle)

            this._bmp.rotation = angle
        }
    }

    public Release() {
        if (this._joint != null) {
            this._world.DestroyJoint(this._joint)
        }
        if (this._bmp != null) {
            this._container.removeChild(this._bmp)
            this._bmp = null
        }
    }
}